package com.common.weapp.controller;


import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.common.constants.WeConstants;
import com.common.user.domain.User;
import com.common.user.service.UserService;
import com.common.weapp.bean.WeJscode2SessionResult;
import com.common.weapp.bean.WeUser;
import com.common.weapp.service.WeTokenService;
import com.common.weapp.service.WeUserService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;


/**
 * We user api
 * @author enbool
 *
 */
@Api(description = "Manage WeChat user")
@RestController
@RequestMapping(value = "/we")
public class WeuserController {
	
	@Autowired
	private WeUserService weUserService;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	PasswordEncoder BCryptPasswordEncoder;	
	@Autowired
	private WeTokenService weTokenService;	

	@ApiOperation(value = "login system")
	@ApiImplicitParam(name = "code", value = "The login certificate, generated by WeChat")
    @GetMapping("/login")
    public ResponseEntity<OAuth2AccessToken> login(@RequestParam(required = false) String code, @RequestHeader HttpHeaders headers) throws Exception {
		
		if (StringUtils.  isBlank(code)) {
        	code = headers.getFirst(WeConstants.WX_HEADER_CODE);
        	if (StringUtils.isBlank(code)) {
        		throw new Exception("empty code!");
        	}            
        }
        
    	WeJscode2SessionResult session = weUserService.getSessionInfo(code);
    	
    	WeUser weUser = weUserService.getUserInfo(session.getSessionKey(),
    							headers.getFirst(WeConstants.WX_HEADER_ENCRYPTED_DATA), 
    									headers.getFirst(WeConstants.WX_HEADER_IV));
    	
    	User user = userService.findByUsername(weUser.getOpenId());
		//register a user in system.
		if(user == null) {
			user = new User();			
		}
		WeUserService.weUser2User(user, weUser);
		user.setPassword(BCryptPasswordEncoder.encode(session.getSessionKey()));
		userService.save(user);
		
		Map<String, String> params = new HashMap<>();
	    params.put("grant_type", "password");
	    params.put("scope", "all");
	    params.put("username", weUser.getOpenId());
	    params.put("password", session.getSessionKey());   
	    
	    Authentication authentication = new UsernamePasswordAuthenticationToken(user, null);	    
		OAuth2AccessToken token = weTokenService.createAccessToken(authentication, params);
		
         return getResponse(token);       
    }
	
	@GetMapping("/loadUser")
	@ApiOperation(value = "load user")
	@ApiImplicitParam(name = "code", required = true, value = "The openId of the user to load.")
	public WeUser findByOpenId(@RequestParam String openId) {
		User user = userService.findByUsername(openId);
		if(user == null) {
			return null;
		}
		
		WeUser weUser = new WeUser();
		WeUserService.user2WeUser(user, weUser);
		
		return weUser;
	}

    private ResponseEntity<OAuth2AccessToken> getResponse(OAuth2AccessToken accessToken) {
		HttpHeaders headers = new HttpHeaders();
		headers.set("Cache-Control", "no-store");
		headers.set("Pragma", "no-cache");
		return new ResponseEntity<OAuth2AccessToken>(accessToken, headers, HttpStatus.OK);
	}
}
